package com.ctrip.ec.api.mobile.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.ctrip.ec.api.mobile.config.AlipayConfig;
import com.ctrip.ec.api.mobile.common.JsonBody;
import com.ctrip.ec.api.mobile.common.RequestContext;
import com.ctrip.ec.api.mobile.service.payment.AgentWxPayServiceCache;
import com.ctrip.ec.biz.dao.agent.AgentDao;
import com.ctrip.ec.biz.dao.goods.GoodsDao;
import com.ctrip.ec.biz.dao.goods.GoodsRebateDao;
import com.ctrip.ec.biz.dao.member.MemberDao;
import com.ctrip.ec.biz.dao.order.OrderDao;
import com.ctrip.ec.biz.dao.order.OrderGoodsDao;
import com.ctrip.ec.biz.dao.payment.PaymentDao;
import com.ctrip.ec.biz.dao.rebate.RebateHistoryDao;
import com.ctrip.ec.biz.entity.goods.GoodsRebateEntity;
import com.ctrip.ec.biz.entity.member.MemberEntity;
import com.ctrip.ec.biz.entity.order.OrderEntity;
import com.ctrip.ec.biz.entity.order.OrderGoodsEntity;
import com.ctrip.ec.biz.entity.order.OrderStatus;
import com.ctrip.ec.biz.entity.payment.PaymentEntity;
import com.ctrip.ec.biz.entity.payment.PaymentStatus;
import com.ctrip.ec.biz.entity.payment.PaymentType;
import com.ctrip.ec.biz.entity.payment.PaymentPurpose;
import com.ctrip.ec.biz.entity.rebate.RebateHistoryEntity;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * Created by jiang on 2018/10/7.
 */
@RestController
@RequestMapping("notify")
public class NotifyController {

    @Autowired
    private WxPayService wxService;

    @Autowired
    private PaymentDao payment;

    @Autowired
    private OrderDao order;

    @Autowired
    private OrderGoodsDao orderGoods;

    @Autowired
    private MemberDao member;

    @Autowired
    private RebateHistoryDao rebateHistory;

    @Autowired
    private GoodsDao goods;

    @Autowired
    private GoodsRebateDao goodsRebate;

    @Autowired
    private AlipayConfig alipayConfig;

    @Autowired
    private AgentWxPayServiceCache wxPayServiceCache;

    @Autowired
    private AgentDao agent;


    private final static Logger logger = LoggerFactory.getLogger(NotifyController.class);

    //mvn install:install-file -DgroupId=com.alipay -DartifactId=sdk-java -Dversion=3.3.1 -Dpackaging=jar -Dfile=alipay-sdk-java-3.3.1.jar
    //mvn install:install-file -DgroupId=com.alipay -DartifactId=commons-logging -Dversion=1.1.1 -Dpackaging=jar -Dfile=commons-logging-1.1.1.jar


    @PostMapping("wechat")
    @JsonBody(false)
    public String wechat(@RequestBody String xmlData) throws WxPayException, SQLException {

        logger.info(xmlData);
        WxPayOrderNotifyResult result = this.wxService.parseOrderNotifyResult(xmlData);//这里已经校验了

//        try {
//            //  Map<String,String> map =  result.toMap();
//            result.checkResult(wxService, "MD5", true);
//
//        } catch (WxPayException ex) {
//            logger.error(ex.getMessage(), ex);
//            throw ex;
//        }

        String outTradeNo = result.getOutTradeNo();
        Integer totalFee = result.getTotalFee();//单位为分,除了核对好像没什么用
        String tranctionId = result.getTransactionId();


        PaymentEntity paymentEntity = payment.entityBySn(outTradeNo);

        if (paymentEntity == null) {
            logger.error("支付订单" + outTradeNo + "不存在");
            throw new RuntimeException("支付订单" + outTradeNo + "不存在");
        }

        //支付幂等
        if (paymentEntity.getStatus() == PaymentStatus.已支付.ordinal()) {
            logger.info("repeat notice");
            return WxPayNotifyResponse.success("OK");
        }

        paymentEntity.setTransactionId(tranctionId);
        paymentEntity.setStatus(PaymentStatus.已支付.ordinal());
        paymentEntity.setName("微信支付");
        paymentEntity.setType(PaymentType.微信.ordinal());
        paymentEntity.setPurpose(PaymentPurpose.定单.ordinal());

        MemberEntity memberEntity = member.entity(paymentEntity.getMemberId());


        try {
            payment.getDb().begin();
            payment.save(paymentEntity);

            //打到下面的所有order
            List<OrderEntity> list = order.list("payment_id = " + paymentEntity.getId());
            for (OrderEntity orderEntity : list) {
                orderEntity.setOrderStatus(OrderStatus.待发货.getId());
                order.save(orderEntity);
            }


            BigDecimal rebate = new BigDecimal(0);//返现计算

            for (OrderEntity orderEntity : list) {
                List<OrderGoodsEntity> goodsList = orderGoods.listByOrderId(orderEntity.getId());

                GoodsRebateEntity rebateEntity = goodsRebate.entity(orderEntity.getId(), memberEntity.getLevel());

                for (OrderGoodsEntity orderGoodsEntity : goodsList) {

                    if (rebateEntity != null) {
                        Integer rebateTypeId = orderGoodsEntity.getRebateTypeId();
                        if (rebateTypeId == 0) {//固定值
                            rebate.add(new BigDecimal(rebateEntity.getVal()).multiply(new BigDecimal(orderGoodsEntity.getBuyNum())));
                        } else { //按比例
                            rebate.add(orderGoodsEntity.getShopPrice().multiply(new BigDecimal(orderGoodsEntity.getBuyNum())).multiply(new BigDecimal(rebateEntity.getVal())).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                        }
                    }
                }
            }

            //保存返现
            if (memberEntity.getRebate() != null) {
                rebate = rebate.add(memberEntity.getRebate());
            }
            memberEntity.setRebate(rebate);
            memberEntity.setTotalAmount(memberEntity.getTotalAmount().add(paymentEntity.getGoodsAmount()));//不包括运费
            member.save(memberEntity);

            //保存返现历史
            RebateHistoryEntity rebateHistoryEntity = new RebateHistoryEntity();
            rebateHistoryEntity.setRebate(rebate);
            rebateHistoryEntity.setCreateTime(new Timestamp(System.currentTimeMillis()));
            rebateHistoryEntity.setMemberId(RequestContext.getMemberId());
            rebateHistoryEntity.setPaymentId(paymentEntity.getId());
            rebateHistory.save(rebateHistoryEntity);

            payment.getDb().commit();
            String response = WxPayNotifyResponse.success("OK");
            logger.info(result.getOutTradeNo() + "call back success");
            return response;
        } catch (Exception ex) {
            payment.getDb().rollback();
            logger.error(ex.getMessage(), ex);
            throw ex;
        }

    }

    /**
     * 小程序支付回调
     * @param xmlData
     * @return
     * @throws WxPayException
     * @throws SQLException
     */
    @PostMapping("miniapp")
    @JsonBody(false)
    public  String miniapp(@RequestBody String xmlData) throws WxPayException, SQLException, ExecutionException {

        //SAXReader
        logger.info("miniapp|" + xmlData);

        WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);

      //  WxPayOrderNotifyResult result = this.wxService.parseOrderNotifyResult(xmlData);
       //                          result = payExService.parseOrderNotifyResult(xmlData);
        // result.checkResult(this, this.getConfig().getSignType(), false);

        Integer totalFee = result.getTotalFee();//单位为分,除了核对好像没什么用
        String tranctionId = result.getTransactionId();

        String outTradeNo = result.getOutTradeNo();
        PaymentEntity paymentEntity = payment.entityBySn(outTradeNo);
        if (paymentEntity == null) {
            logger.error("支付订单" + outTradeNo + "不存在");
            throw new RuntimeException("支付订单" + outTradeNo + "不存在");
        }


        WxPayService service = wxPayServiceCache.wxPayService(paymentEntity.getAgentId());
        if(service == null){
            logger.error("agentId:" + paymentEntity.getAgentId() + " can not find data");
            throw new RuntimeException("error");
        }

        try {
            //  Map<String,String> map =  result.toMap();
            result.checkResult(service, "MD5", true);

        } catch (WxPayException ex) {
            logger.error(ex.getMessage(), ex);
            throw ex;
        }

        //支付幂等
        if (paymentEntity.getStatus() == PaymentStatus.已支付.ordinal()) {
            logger.info("repeat notice");
            return WxPayNotifyResponse.success("OK");
        }

        paymentEntity.setTransactionId(tranctionId);
        paymentEntity.setStatus(PaymentStatus.已支付.ordinal());
        paymentEntity.setName("微信支付");
        paymentEntity.setType(PaymentType.微信.ordinal());
        paymentEntity.setPurpose(PaymentPurpose.定单.ordinal());
        MemberEntity memberEntity = member.entity(paymentEntity.getMemberId());


        try {
            payment.getDb().begin();
            payment.save(paymentEntity);

            //// TODO: 2018/11/23  需要扣除代理商的余额
            agent.consume(paymentEntity.getPaymentAmount(),paymentEntity.getAgentId());

            //打到下面的所有order
            List<OrderEntity> list = order.list("payment_id = " + paymentEntity.getId());
            for (OrderEntity orderEntity : list) {
                orderEntity.setOrderStatus(OrderStatus.待发货.getId());
                order.save(orderEntity);
            }


            BigDecimal rebate = new BigDecimal(0);//返现计算

            for (OrderEntity orderEntity : list) {
                List<OrderGoodsEntity> goodsList = orderGoods.listByOrderId(orderEntity.getId());

                GoodsRebateEntity rebateEntity = goodsRebate.entity(orderEntity.getId(), memberEntity.getLevel());

                for (OrderGoodsEntity orderGoodsEntity : goodsList) {

                    if (rebateEntity != null) {
                        Integer rebateTypeId = orderGoodsEntity.getRebateTypeId();
                        if (rebateTypeId == 0) {//固定值
                            rebate.add(new BigDecimal(rebateEntity.getVal()).multiply(new BigDecimal(orderGoodsEntity.getBuyNum())));
                        } else { //按比例
                            rebate.add(orderGoodsEntity.getShopPrice().multiply(new BigDecimal(orderGoodsEntity.getBuyNum())).multiply(new BigDecimal(rebateEntity.getVal())).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                        }
                    }
                }
            }

            //保存返现
            if (memberEntity.getRebate() != null) {
                rebate = rebate.add(memberEntity.getRebate());
            }
            memberEntity.setRebate(rebate);
            memberEntity.setTotalAmount(memberEntity.getTotalAmount().add(paymentEntity.getGoodsAmount()));//不包括运费
            member.save(memberEntity);

            //保存返现历史
            RebateHistoryEntity rebateHistoryEntity = new RebateHistoryEntity();
            rebateHistoryEntity.setRebate(rebate);
            rebateHistoryEntity.setCreateTime(new Timestamp(System.currentTimeMillis()));
            rebateHistoryEntity.setMemberId(RequestContext.getMemberId());
            rebateHistoryEntity.setPaymentId(paymentEntity.getId());
            rebateHistory.save(rebateHistoryEntity);

            payment.getDb().commit();
            String response = WxPayNotifyResponse.success("OK");
            logger.info(result.getOutTradeNo() + "call back success");
            return response;
        } catch (Exception ex) {
            payment.getDb().rollback();
            logger.error(ex.getMessage(), ex);
            throw ex;
        }
    }

    @PostMapping("alipay")
    @JsonBody(false)
    public String alipay(@RequestBody String json, HttpServletRequest request) throws SQLException {
        Map<String, String> params = new HashMap<String, String>();
        StringBuilder sb = new StringBuilder();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
            sb.append(name + "=" + valueStr + "&");
        }
        logger.info(sb.toString());
//切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        boolean flag = false;
        try {

            flag = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), AlipayConstants.CHARSET_UTF8, "RSA2");
            if (flag) {
//                1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
//                2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
//                3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email），
//                4、验证app_id是否为该商户本身。
                String outTradeNo = params.get("out_trade_no");
                String appId = params.get("app_id");
                String notifyId = params.get("notify_id");


                PaymentEntity paymentEntity = payment.entityBySn(outTradeNo);

                if (paymentEntity == null) {
                    logger.error("支付订单" + outTradeNo + "不存在");
                    throw new RuntimeException("支付订单" + outTradeNo + "不存在");
                }

                //支付幂等
                if (paymentEntity.getStatus() == PaymentStatus.已支付.ordinal()) {
                    logger.info("repeat notice");
                    return WxPayNotifyResponse.success("OK");
                }

                paymentEntity.setTransactionId(notifyId);
                paymentEntity.setStatus(PaymentStatus.已支付.ordinal());
                paymentEntity.setName("支付宝支付");
                paymentEntity.setType(PaymentType.支付宝.ordinal());
                paymentEntity.setPurpose(PaymentPurpose.定单.ordinal());

                MemberEntity memberEntity = member.entity(paymentEntity.getMemberId());


                try {
                    payment.getDb().begin();
                    payment.save(paymentEntity);

                    //打到下面的所有order
                    List<OrderEntity> list = order.list("payment_id = " + paymentEntity.getId());
                    for (OrderEntity orderEntity : list) {
                        orderEntity.setOrderStatus(OrderStatus.待发货.getId());
                        order.save(orderEntity);
                    }


                    BigDecimal rebate = new BigDecimal(0);//返现计算

                    for (OrderEntity orderEntity : list) {
                        List<OrderGoodsEntity> goodsList = orderGoods.listByOrderId(orderEntity.getId());

                        GoodsRebateEntity rebateEntity = goodsRebate.entity(orderEntity.getId(), memberEntity.getLevel());

                        for (OrderGoodsEntity orderGoodsEntity : goodsList) {

                            if (rebateEntity != null) {
                                Integer rebateTypeId = orderGoodsEntity.getRebateTypeId();
                                if (rebateTypeId == 0) {//固定值
                                    rebate.add(new BigDecimal(rebateEntity.getVal()).multiply(new BigDecimal(orderGoodsEntity.getBuyNum())));
                                } else { //按比例
                                    rebate.add(orderGoodsEntity.getShopPrice().multiply(new BigDecimal(orderGoodsEntity.getBuyNum())).multiply(new BigDecimal(rebateEntity.getVal())).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                                }
                            }
                        }
                    }

                    //保存返现
                    if (memberEntity.getRebate() != null) {
                        rebate = rebate.add(memberEntity.getRebate());
                    }
                    memberEntity.setRebate(rebate);
                    memberEntity.setTotalAmount(memberEntity.getTotalAmount().add(paymentEntity.getGoodsAmount()));//不包括运费
                    member.save(memberEntity);

                    //保存返现历史
                    RebateHistoryEntity rebateHistoryEntity = new RebateHistoryEntity();
                    rebateHistoryEntity.setRebate(rebate);
                    rebateHistoryEntity.setCreateTime(new Timestamp(System.currentTimeMillis()));
                    rebateHistoryEntity.setMemberId(RequestContext.getMemberId());
                    rebateHistoryEntity.setPaymentId(paymentEntity.getId());
                    rebateHistory.save(rebateHistoryEntity);

                    payment.getDb().commit();
                    String response = WxPayNotifyResponse.success("OK");
                    logger.info(outTradeNo + "call back success");
                    return "success";
                } catch (Exception ex) {
                    payment.getDb().rollback();
                    logger.error(ex.getMessage(), ex);
                    throw ex;
                }
            } else {
                logger.info("rsaCheckV1 fail");
            }
        } catch (AlipayApiException e) {
            logger.error(e.getMessage(), e);
            e.printStackTrace();
        }
        return "fail";
    }



}
